#include "SymbolTable.h"
#include <list>
using namespace std;

namespace name_OP {
    enum Operator {
        LAB,    // 标签
        FUNC,   // 定义函数
        PROC,   // 定义过程
        ASS,    // 赋值
        ADD,    // 加法
        SUB,    // 减法
        MUL,    // 乘法
        DIV,    // 除法
        MOD,    //取模
        DIVISION, //取余
        INTTOREAL,//int to real
        NOT,    //!
        ASTA,   //*dest = oper1
        ASFA,   //dest = *oper1
        EQUAL,  //等于
        NEQUAL, //不等于
        LESS,   //小于
        LE,     //小于等于
        GREATER,//大于 
        GE,     //大于等于
        AND,    //与
        OR,     //或
        CMP,    // 比较
        JG,     // 大于跳转
        JGE,    // 大于或等于跳转
        JL,     // 小于跳转
        JLE,    // 小于或等于跳转
        JE,     // 等于跳转
        JNE,    // 不等于跳转
        JMP,    // 无条件跳转       
        CALP,   // 过程调用，不带返回值
        CALF,   // 函数调用，带返回值
        RETURN, // 函数返回
        ARG,    // 传实参
        REF,    // 传引用
        PARAM,  // 函数参数声明
        RI,     // 读整数
        RC,     // 读字符
        RF,     // 读浮点数
        WS,     // 写字符串
        WI,     // 写整数
        WC,     // 写字符
        WF,     // 写浮点数
        NL,      // 换行
        END,
    };
}
using name_OP::Operator;

class Quadruple{
    friend std::ostream& operator<<(std::ostream&, const Quadruple&);
public:
    string dest;
    string op1;
    string op2;
    Operator op;
    Quadruple(){}
    Quadruple(const string d, const string p1, Operator op, const string p2){
        this->dest = d;
        this->op1 = p1;
        this->op = op;
        this->op2 = p2;
    }

    void print(){
        if(op == Operator::LAB){
            cout << "Label: " << op1;
        }
        else if(op == Operator::FUNC){
            cout << "Function: " << dest;
        }
        else if(op == Operator::PROC){
            cout << "Procedure: " << dest;
        }
        else if(op == Operator::ASS){
            cout << dest << " := " << op1;
        }
        else if(op == Operator::ADD){
            cout << dest << " := " << op1 << " + " << op2;
        }
        else if(op == Operator::SUB){
            cout << dest << " := " << op1 << " - " << op2;
        }
        else if(op == Operator::MUL){
            cout << dest << " := " << op1 << " * " << op2;
        }        
        else if(op == Operator::DIV){
            cout << dest << " := " << op1 << " / " << op2;
        }
        else if(op == Operator::MOD){
            cout << dest << " := " << op1 << " % " << op2;
        }
        else if(op == Operator::DIVISION){
            cout << dest << " := " << op1 << " // " << op2;
        }
        else if(op == Operator::INTTOREAL){
            cout << dest << " := " << " Int to Real " << op1; 
        }
        else if(op == Operator::NOT){
            cout << dest << " := " << " ! " << op1; 
        }
        else if(op == Operator::ASFA){
            cout << dest << " := " << " *" << op1; 
        }
        else if(op == Operator::ASTA){
            cout << " *" << dest << " := " << op1; 
        }
        else if(op == Operator::EQUAL){
            cout << dest << " := " << op1 << " == " << op2;
        }
        else if(op == Operator::NEQUAL){
            cout << dest << " := " << op1 << " != " << op2;
        }
        else if(op == Operator::LESS){
            cout << dest << " := " << op1 << " < " << op2;
        }
        else if(op == Operator::LE){
            cout << dest << " := " << op1 << " <= " << op2;
        }
        else if(op == Operator::GREATER){
            cout << dest << " := " << op1 << " > " << op2;
        }
        else if(op == Operator::GE){
            cout << dest << " := " << op1 << " >= " << op2;
        }
        else if(op == Operator::AND){
            cout << dest << " := " << op1 << " & " << op2;
        }
        else if(op == Operator::OR){
            cout << dest << " := " << op1 << " | " << op2;
        }
        else if(op == Operator::CMP){
            cout << dest << " := " << op1 << " ? " << op2;
        }
        else if(op == Operator::JG){
            cout << "if " << op1 << " > " << 0 << " goto " << op2;
        }
        else if(op == Operator::JL){
            cout << "if " << op1 << " < " << 0 << " goto " << op2;
        }
        else if(op == Operator::JGE){
            cout << "if " << op1 << " >= " << 0 << " goto " << op2;
        }
        else if(op == Operator::JLE){
            cout << "if " << op1 << " <= " << 0 << " goto " << op2;
        }
        else if(op == Operator::JE){
            cout << "if " << op1 << " == " << 0 << " goto " << op2;
        }
        else if(op == Operator::JNE){
            cout << "if " << op1 << " != " << 0 << " goto " << op2;
        }
        else if(op == Operator::JMP){
            cout << "goto " << op2;
        }
        else if(op == Operator::CALP){
            cout << "call procedure " << dest; 
        }
        else if(op == Operator::CALF){
            cout << dest << " := " << "call function " << op1;
        }
        else if(op == Operator::RETURN){
            cout << "return " << dest;
        }
        else if(op == Operator::ARG){
            cout << "push " << dest;
        }
        else if(op == Operator::REF){
            cout << "push var" << dest;
        }
        else if(op == Operator::PARAM){
            cout << "parameter " << dest;
        }
        else if(op == Operator::RI){
            cout << "RI " << dest;
        }
        else if(op == Operator::RC){
            cout << "RC " << dest;
        }
        else if(op == Operator::RF){
            cout << "RF " << dest;
        }
        else if(op == Operator::WS){
            cout << "WS " << dest;
        }
        else if(op == Operator::WI){
            cout << "WI " << dest;
        }
        else if(op == Operator::WC){
            cout << "WC " << dest;
        }        
        else if(op == Operator::WF){
            cout << "WF " << dest;
        }
        else if(op == Operator::NL){
            cout << "NL";
        }
        else if(op == Operator::END){
            cout << "END";
        }
        cout << endl << endl;
    }

    void println(std::ostream &os) {
        os << *this << '\n';
    }

};

list<Quadruple*> GET_PPROGRAM(const Program* program);

//using Quads = list<Quadruple*>;